#include "Utils.h"
#include "stb_image.h"
#include <direct.h>
#include <glad/glad.h>
#include <iostream>

Utils::Utils() {
}

glm::vec3 Utils::RGBToFloat(int R, int G, int B) {
    return glm::vec3((float) R / 255.0f, (float) G / 255.0f, (float) B / 255.0f);
}

std::string Utils::GetResourceDir() {
    char buffer[_MAX_PATH];
    _getcwd(buffer, _MAX_PATH);
    std::string path = buffer;
    return path.substr(0, path.find_last_of("\\"));
}

unsigned int Utils::loadTexture(const char *path) {
    unsigned int textureID;
    glGenTextures(1, &textureID);

    int width, height, nrComponents;
    unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
    if (data) {
        GLenum format;
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        /**
         * 当采样纹理的边缘的时候，OpenGL会对边缘的值和纹理下一个重复的值进行插值（因为我们将它的环绕方式设置为了GL_REPEAT。
         * 这通常是没问题的，但是由于我们使用了透明值，纹理图像的顶部将会与底部边缘的纯色值进行插值。这样的结果是一个半透明的有色边框，
         * 你可能会看见它环绕着你的纹理四边形。要想避免这个，每当你alpha纹理的时候，请将纹理的环绕方式设置为GL_CLAMP_TO_EDGE：
         */
         //https://www.jianshu.com/p/1829b4acc58d
        /**
            纹理坐标的范围与OpenGL的屏幕坐标范围一样，是0-1。超出这一范围的坐标将被OpenGL根据GL_TEXTURE_WRAP参数的值进行处理:
            (环绕方式)
            GL_REPEAT: 超出纹理范围的坐标整数部分被忽略，形成重复效果。
            GL_MIRRORED_REPEAT: 超出纹理范围的坐标整数部分被忽略，但当整数部分为奇数时进行取反，形成镜像效果。
            GL_CLAMP_TO_EDGE:超出纹理范围的坐标被截取成0和1，形成纹理边缘延伸的效果。
            GL_CLAMP_TO_BORDER: 超出纹理范围的部分被设置为边缘色。

            纹理尺寸与模型尺寸不符的情况，这时，纹理会因为缩放而失真。处理这一失真的过程我们称为过滤
            （多级渐远）
            GL_NEAREST: 最临近过滤，获得最靠近纹理坐标点的像素。
            GL_LINEAR: 线性插值过滤，获取坐标点附近4个像素的加权平均值。
            GL_NEAREST_MIPMAP_NEAREST：选择最邻近的mip层，并使用最邻近过滤。
            GL_NEAREST_MIPMAP_LINEAR：对两个mip层使用最邻近过滤后的采样结果进行加权平均。
            GL_LINEAR_MIPMAP_NEAREST：选择最邻近的mip层，使用线性插值算法进行过滤。
            GL_LINEAR_MIPMAP_LINEAR：对两个mip层使用线性插值过滤后的采样结果进行加权平均，又称三线性mipmap。
         */
         //纹理坐标范围不一致是的环绕方式
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT); // for this tutorial: use GL_CLAMP_TO_EDGE to prevent semi-transparent borders. Due to interpolation it takes texels from next repeat
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, format == GL_RGBA ? GL_CLAMP_TO_EDGE : GL_REPEAT);
       //纹理尺寸不符合时的处理方式，过滤( 其中之一---mipmap 多级渐远)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        stbi_image_free(data);
    } else {
        std::cout << "Texture failed to load at path: " << path << std::endl;
        stbi_image_free(data);
    }

    return textureID;
}

